package com.bb.blog.security;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import tk.mybatis.spring.annotation.MapperScan;

/**
 *  认证中心
 *
 *  AUTHORIZATION_CODE 模式
 *
 *  1. 用户访问服务A 需要使用服务B的数据
 *
 *  2. 在点击后发现没有权限, 则跳转服务B的登录界面要求授权
 *      2.2  即访问服务B的   {baseUrl}/oauth2/authorization/{registrationId}
 *      2.3  这时服务B的角色为client, 经过 OAuth2AuthorizationRequestRedirectFilter
 *      2.4 OAuth2AuthorizationRequestResolver 接口的Bean会找到认证请求地址以及参数，如果能正确的找到参数就会发送重定向
 *          2.4.1 从request中获取registrationId 并交给 ClientRegistrationRepository . findById 方法去查找配置文件或者Java中配置的Client
 *          2.4.2 交给Builder 创建authorizedRequest
 *          2.4.3 AuthorizationRequestRepository ，是基于session做安全认证确保回调的对象是认证中心
 *
 *  3. 认证中心收到认证请求 /oauth/authorize  由默认的AuthorizationEndpoint来处理
 *      3.0 此时认证中心本身的认证系统需要先认证当前用户的身份，在跳转的授权页面
 *      3.1 将所有参数都放到AuthorizationRequest里
 *      3.2 ClientDetailsService通过clientId 查找ClientDetail
 *      3.3 设置好回调地址，这个地址是从clientDetail 和 服务A中的配置共同决定的  默认的地址是 /login/oauth2/code/{code}
 *      3.4 返回到A系统中的地址
 *
 *  4. 获取到code后 进入到AbstractAuthenticationProcessingFilter中
 *      4.1 首先判断授权码和授权状态是否包含在参数里 并从上文中的 AuthorizationRequestRepository 去找与这个请求成对的请求
 *      4.2 ClientRegistrationRepository  查找对应的ClientRegistration
 *      4.3 将request 和 response 组装成OAuth2LoginAuthenticationToken 交给 AuthenticationManager 认证
 *      4.4 AuthenticationManager 委托给 Oauth2LoginAuthenticationProvider来认证
 *          4.4.1 使用 request里的 ClientRegistration 和 Exchange 构造 OAuth2AuthorizationCodeGrantRequest
 *          4.4.2 AccessTokenResponseClient 获取Token  访问认证中心的 oauth/token接口
 *          4.4.3 通过 token 获取用户信息 /oauth/user
 *  5. oauth/token
 *      5.1 通过 ClientCredentialsTokenEndPointFilter 来校验clientId 和 clientSecret
 *      5.2 通过TokenGranter 来生成Token  原理与AuthenticationManager类似 根据不同的grantType转发给不同类处理
 *      5.3 交给TokenServices 来创建 这里比较复杂 要处理token的逻辑 token
 *      5.4 返回token
 *  6.oauth/user
 *      这是自定义的的
 *
 *  7.
 *
 */

@SpringBootApplication(scanBasePackages = "com.bb.blog")
@EnableAuthorizationServer
@EnableWebSecurity(debug = true)
@MapperScan("com.bb.blog.security.dao")
@EnableCaching
public class SecurityApplication {


    public static void main(String[] args) {
        SpringApplication.run(SecurityApplication.class, args);
    }

}

